# Copyright (c) 2021-2023 Alibaba Cloud Computing Ltd.
# SPDX-License-Identifier: MulanPSL-2.0

import logging
import functools
import traceback

CALL_LEVEL = -1
PLACEHOLDER = " " * 4

def functionLog(func):
    """ Auto logging decorator to function calling

    Function is excepeted return tuple as (suc, data).
    Logging arguements of this function and return value.
    Handling all exception occured in this function, logging traceback and return False.

    """
    @functools.wraps(func)
    def wrapper(*args, **kw):
        global CALL_LEVEL, PLACEHOLDER
        CALL_LEVEL += 1
        logger = logging.getLogger("auto")
        logger.debug("{placeholder}[{module}.{func}] << {args} {kw}".format(
                    placeholder = PLACEHOLDER*CALL_LEVEL,
                    module      = func.__module__,
                    func        = func.__qualname__,
                    args        = ",".join(["{}".format(_arg) for _arg in args]),
                    kw          = ",".join(["{} = {}".format(k, v) for k, v in kw.items()])))

        try:
            out = func(*args, **kw)

        except Exception as e:
            logger.error('[{module}.{func}] {trace}'.format(
                module  = func.__module__,
                func    = func.__qualname__,
                trace   = traceback.format_exc()))
            CALL_LEVEL -= 1
            raise

        else:
            logger.debug("{placeholder}[{module}.{func}] >> {out}".format(
                placeholder = PLACEHOLDER*CALL_LEVEL,
                module      = func.__module__,
                func        = func.__qualname__,
                out         = out
            ))
            CALL_LEVEL -= 1
            return out
    return wrapper